import React, { Component } from 'react';
import classnames from 'classnames';
import Touch from 'components/Touch/core';
import PropTypes from 'prop-types';
import Style from './index.m.less';

function closest(el, selector) {
    const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;

    while (el) {
        if (matchesSelector.call(el, selector)) {
            return el;
        }
        el = el.parentElement;
    }
    return null;
}

export default class extends Component {
    static defaultProps = {
        autoClose: false,
        disabled: false,
        right: [],
        onOpen() {},
        onClose() {},
        className: null,
        children: null,
    };

    static propTypes = {
        autoClose: PropTypes.bool,
        disabled: PropTypes.bool,
        right: PropTypes.array,
        onOpen: PropTypes.func,
        onClose: PropTypes.func,
        className: PropTypes.string,
        children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
    };

    state = {
        active: false,
    };

    // eslint-disable-next-line react/sort-comp
    setRef = d => {
        this.dom = d;
    };

    setActionsRef = r => {
        this.actionsRef = r;
    };

    componentDidMount() {
        this.isOpen = false; // 初始化时为关闭状态
        if (this.dom) {
            this.addEventListener();
        }
    }

    componentWillUnmount() {
        this.touch && this.touch.destroy();
        document.body.removeEventListener('touchstart', this.reset, true);
    }

    addEventListener() {
        const maxActionsWidth = this.actionsRef.offsetWidth;
        this.touch = new Touch(this.dom, {
            preventDefault: false,
        })
            .on('nativeStart', () => {
                this.isSwiping = true;
            })
            .on('change', (change, state, event) => {
                if (state.direction === 'lr') {
                    if (!this.isSwiping) return;
                    event.preventDefault();
                    const delta = Math.max(-maxActionsWidth, change.x);
                    this.changeTrans(delta);
                }
            })
            .on('end', (change, done, state, event) => {
                if (state.direction === 'lr') {
                    if (!this.isSwiping) return;
                    this.isSwiping = false;
                    event.preventDefault();
                    let delta = 0;
                    if (Math.abs(change.x) > maxActionsWidth / 2) {
                        delta = -maxActionsWidth;
                        this.open();
                    } else {
                        this.close();
                    }
                    const active = delta !== 0;
                    this.changeTrans(delta, true);
                    this.setState({
                        active,
                    });
                }
                done();
            });
        document.body.addEventListener('touchstart', this.reset, true);
    }

    changeTrans(x, animation = false) {
        x = Math.min(0, x);
        if (!this.dom) return;
        if (!animation) {
            this.dom.style.cssText += `
                transition: none;
                -webkit-transiton: none;
            `;
        } else {
            this.dom.style.cssText += `
                transition: transform .3s;
                -webkit-transiton: -webkit-transform .3s;
            `;
        }
        this.dom.style.cssText += `
            transform: translateX(${x}px);
            -webkit-transform: translateX(${x}px);
        `;
        if (this.cover) {
            this.cover.style.display = Math.abs(x) > 0 ? 'block' : 'none';
            this.cover.style.left = `${x}px`;
        }
    }

    open() {
        if (!this.isOpen && this.props.onOpen) {
            this.props.onOpen();
        }
        this.changeTrans(this.actionsRef.offsetWidth, true);
        this.isOpen = true;
    }

    close() {
        if (this.isOpen && this.props.onClose) {
            this.props.onClose();
        }
        this.changeTrans(0, true);
        this.isOpen = false;
    }

    reset = e => {
        if (!this.isOpen) return;
        const pNode = closest(e.target, '.buttons');
        if (pNode) return;
        e.preventDefault();
        if (!this.dom) return;
        this.close();
    };

    onClick(e, item) {
        item.onPress && item.onPress();
        const { autoClose } = this.props;
        if (autoClose) {
            this.close();
        }
    }

    render() {
        const {
            className,
            // eslint-disable-next-line react/prop-types
            style,
            right = [],
            disabled,
            children,
        } = this.props;
        const { active } = this.state;
        return (
            <div style={style} className={classnames(active ? `${className} wpt-swipe` : className, Style.swipe)}>
                <div
                    className={Style.cover}
                    ref={el => {
                        this.cover = el;
                    }}
                />
                {right && (
                    <div className={classnames(Style.actions, 'buttons')} ref={this.setActionsRef}>
                        {right.map(item => (
                            <div className={Style.btn} key={item.text} style={item.style}>
                                <div
                                    style={Style.txt}
                                    className={classnames(Style['actions-btn'], item.className)}
                                    onClick={e => this.onClick(e, item)}
                                >
                                    {item.text}
                                </div>
                            </div>
                        ))}
                    </div>
                )}
                <div ref={disabled ? null : this.setRef} className={Style.content}>
                    {children}
                </div>
            </div>
        );
    }
}
